import { AnyFunc } from "./type";
import Reflect from "@/utils/reflect";

type RequestMethod<P extends any[], R> = (this: any, ...args: P) => Promise<R>;

/** 合并接口请求 */
export function RequestMerge<P extends any[], R>(getKey?: (...args: P) => string, timeout?: number) {

  return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<RequestMethod<P, R>>) {
    Reflect.setValue(target, ["RequestMerge", propertyKey], descriptor.value);

    descriptor.value = function() {
      const promiseMap: Map<string, Promise<R>> = new Map();

      return async function (...args) {
        // 计算键值
        const key = !getKey ? "" : getKey(...args);
        // 返回存在结果
        if (promiseMap.has(key)) {
          return promiseMap.get(key) as Promise<R>;
        }
        // 补充不存在的结果
        let reslove: Function = () => {};
        let reject: Function = () => {};
        const promise = new Promise<R>((loc_reslove, loc_reject) => {
          reslove = loc_reslove;
          reject = loc_reject;
        });
        promiseMap.set(key, promise);
        // 获取定时器
        let timeId = Reflect.getValue<undefined | number | NodeJS.Timeout>(this, ["RequestMergeTimeId", propertyKey, key], undefined);
        // 清除定时器
        if (timeId) {
          clearTimeout(timeId);
          timeId = undefined;
        }
        // 创建定时器
        timeId = setTimeout(() => {
          Reflect.getValue<AnyFunc>(target, ["RequestMerge", propertyKey]).call(this, ...args).then((result: R) => {
            reslove(result);
          }).catch((error: Error) => {
            reject(error);
          });
          // 查询接口完毕清除缓存
          promiseMap.delete(key);
        }, timeout);
        Reflect.setValue(this, ["RequestMergeTimeId", propertyKey, key], timeId);
        // 返回补充结果
        return promise;
      };
    }();

  };

}
